package com.example.service.impl;

import com.example.handler.RiskHandlerChain;
import com.example.mapper.LoginLogMapper;
import com.example.mapper.OperationLogMapper;
import com.example.mapper.PaymentRecordMapper;
import com.example.mapper.TransferRecordMapper;
import com.example.model.BlockchainOp;
import com.example.model.FraudDetectionInput;
import com.example.model.FraudRiskResult;
import com.example.model.UserProfile;
import com.example.model.pojo.LoginLog;
import com.example.model.pojo.OperationLog;
import com.example.model.pojo.PaymentRecord;
import com.example.model.pojo.TransferRecord;
import com.example.service.AiService;
import com.example.service.FraudDetectionService;
import com.example.service.UserService;
import com.example.utils.WeBASEUtils;
import io.github.pigmesh.ai.deepseek.core.DeepSeekClient;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionRequest;
import io.github.pigmesh.ai.deepseek.core.chat.ChatCompletionResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
@Slf4j
public class FraudDetectionServiceImpl implements FraudDetectionService {
  private final WeBASEUtils blockchainService;
  private final PaymentRecordMapper paymentMapper;
  private final AiService aiService;
  private final UserService userService;
  private final LoginLogMapper loginLogMapper;
  private final OperationLogMapper operationLogMapper;
  private final TransferRecordMapper transferRecordMapper;
  private final RiskHandlerChain riskHandlerChain;


  /**
   * 实时欺诈风险检测
   * 
   * @param userAddress 用户地址
   * @return 风险检测结果
   */
  @Override
  public FraudRiskResult detectRealTime(String userAddress) {
    log.info("开始对用户[{}]进行实时欺诈风险检测", userAddress);

    // 从区块链获取最新3条操作
    List<BlockchainOp> ops = blockchainService.getRecentOps(userAddress, 3);

    // 获取用户最近的操作日志和登录日志
    List<OperationLog> operationLogs = operationLogMapper.selectRecentByUser(userAddress, 10);
    List<LoginLog> loginLogs = loginLogMapper.selectRecentByUser(userAddress, 10);
    List<TransferRecord> transferRecords = transferRecordMapper.selectRecentByUser(userAddress, 5);

    // 组合多维度数据
    FraudDetectionInput input = FraudDetectionInput.builder()
        .paymentRecords(paymentMapper.selectLastYear(userAddress))
        .blockchainOps(ops)
        .userProfile(userService.getProfile(userAddress))
        .operationLogs(operationLogs)
        .loginLogs(loginLogs)
        .transferRecords(transferRecords)
        .build();

    // 进行综合分析
    FraudRiskResult result = analyzeWithAI(input);

    // 如果检测到风险，进行风险处理
    if (result.getScore() > 30) {
      handleRisk(result);
    }

    return result;
  }

  /**
   * 身份冒用风险检测
   * 
   * @param userAddress   用户地址
   * @param operationLogs 操作日志
   * @param loginLogs     登录日志
   * @return 风险检测结果
   */
  @Override
  public FraudRiskResult detectIdentityTheft(String userAddress, List<OperationLog> operationLogs,
      List<LoginLog> loginLogs) {
    log.info("开始对用户[{}]进行身份冒用风险检测", userAddress);

    // 获取用户资料
    UserProfile userProfile = userService.getProfile(userAddress);

    // 构建检测输入
    FraudDetectionInput input = FraudDetectionInput.builder()
        .userProfile(userProfile)
        .operationLogs(operationLogs)
        .loginLogs(loginLogs)
        .build();

    // 构建专门针对身份冒用的提示词
    String prompt = String.format("""
        请分析以下用户的身份冒用风险：
        用户特征：%s | 年龄：%d | 参保地：%s
        登录日志：%s
        操作日志：%s
        请重点分析：
        1. 生物特征匹配差异率是否>15%%
        2. 登录设备/地点是否存在突变
        只能按照以下格式输出，不要多，也不要少，风险评分(0-100)、风险类型(1-身份冒用)、风险等级(0-低,1-中,2-高)、证据摘要、建议处置措施
        示例输出：风险评分:85、风险类型:2、风险等级:2、证据摘要:xxx、建议措施:xxx
        """,
        userProfile.getMaskedId(),
        userProfile.getAge(),
        userProfile.getLocation(),
        formatLoginLogs(loginLogs),
        formatOperationLogs(operationLogs));

    // 调用AI分析
    String aiResponse = aiService.chatWithAI(prompt);

    // 解析AI响应
    FraudRiskResult result = parseAIResponse(aiResponse);
    result.setUserAddress(userAddress);
    result.setUserProfile(userProfile);
    result.setDetectionTime(LocalDateTime.now());
    result.setRiskType(1); // 强制设置为身份冒用类型
    result.setRiskTypeDesc("身份冒用");

    return result;
  }

  /**
   * 资金异常风险检测
   * 
   * @param userAddress    用户地址
   * @param paymentRecords 缴费记录
   * @return 风险检测结果
   */
  @Override
  public FraudRiskResult detectFinancialAnomaly(String userAddress, List<PaymentRecord> paymentRecords) {
    log.info("开始对用户[{}]进行资金异常风险检测", userAddress);

    // 获取用户资料
    UserProfile userProfile = userService.getProfile(userAddress);

    // 构建检测输入
    FraudDetectionInput input = FraudDetectionInput.builder()
        .userProfile(userProfile)
        .paymentRecords(paymentRecords)
        .build();

    // 构建专门针对资金异常的提示词
    String prompt = String.format("""
        请分析以下用户的资金异常风险：
        用户特征：%s | 年龄：%d | 参保地：%s
        缴费记录：%s
        请重点分析：
        1. 月缴费基数波动是否>30%%
        2. 缴费频次是否异常（如单日多次缴费）
        只能按照以下格式输出，不要多，也不要少，风险评分(0-100)、风险类型(2-资金异常)、风险等级(0-低,1-中,2-高)、证据摘要、建议处置措施
        示例输出：风险评分:85、风险类型:2、风险等级:2、证据摘要:xxx、建议措施:xxx
        """,
        userProfile.getMaskedId(),
        userProfile.getAge(),
        userProfile.getLocation(),
        formatPaymentData(paymentRecords));

    // 调用AI分析
    String aiResponse = aiService.chatWithAI(prompt);

    // 解析AI响应
    FraudRiskResult result = parseAIResponse(aiResponse);
    result.setUserAddress(userAddress);
    result.setUserProfile(userProfile);
    result.setDetectionTime(LocalDateTime.now());
    result.setRiskType(2); // 强制设置为资金异常类型
    result.setRiskTypeDesc("资金异常");

    return result;
  }

  /**
   * 地域冲突风险检测
   * 
   * @param userAddress     用户地址
   * @param transferRecords 转移记录
   * @param loginLogs       登录日志
   * @return 风险检测结果
   */
  @Override
  public FraudRiskResult detectLocationConflict(String userAddress, List<TransferRecord> transferRecords,
      List<LoginLog> loginLogs) {
    log.info("开始对用户[{}]进行地域冲突风险检测", userAddress);

    // 获取用户资料
    UserProfile userProfile = userService.getProfile(userAddress);

    // 构建检测输入
    FraudDetectionInput input = FraudDetectionInput.builder()
        .userProfile(userProfile)
        .transferRecords(transferRecords)
        .loginLogs(loginLogs)
        .build();

    // 构建专门针对地域冲突的提示词
    String prompt = String.format("""
        请分析以下用户的地域冲突风险：
        用户特征：%s | 年龄：%d | 参保地：%s
        转移记录：%s
        登录日志：%s
        请重点分析：
        1. 是否存在同期多地参保
        2. 转移间隔是否<6个月
        只能按照以下格式输出，不要多，也不要少:风险评分(0-100)、风险类型(3-地域冲突)、风险等级(0-低,1-中,2-高)、证据摘要、建议处置措施
        示例输出：风险评分:85、风险类型:2、风险等级:2、证据摘要:xxx、建议措施:xxx
        """,
        userProfile.getMaskedId(),
        userProfile.getAge(),
        userProfile.getLocation(),
        formatTransferRecords(transferRecords),
        formatLoginLogs(loginLogs));

    // 调用AI分析
    String aiResponse = aiService.chatWithAI(prompt);

    // 解析AI响应
    FraudRiskResult result = parseAIResponse(aiResponse);
    result.setUserAddress(userAddress);
    result.setUserProfile(userProfile);
    result.setDetectionTime(LocalDateTime.now());
    result.setRiskType(3); // 强制设置为地域冲突类型
    result.setRiskTypeDesc("地域冲突");

    return result;
  }

  /**
   * 批量风险检测（定时任务使用）
   * 
   * @return 风险检测结果列表
   */
  @Override
  public List<FraudRiskResult> batchDetection() {
    log.info("开始执行批量欺诈风险检测");

    // 获取需要检测的用户列表（例如最近有活动的用户）
    List<String> userAddresses = userService.getActiveUsers();

    List<FraudRiskResult> results = new ArrayList<>();
    for (String userAddress : userAddresses) {
      try {
        FraudRiskResult result = detectRealTime(userAddress);
        results.add(result);

        // 如果是高风险，立即处理
        if (result.getRiskLevel() == 2) {
          handleRisk(result);
        }
      } catch (Exception e) {
        log.error("对用户[{}]进行批量检测时发生错误", userAddress, e);
      }
    }

    return results;
  }

  /**
   * 处理检测到的风险
   * 
   * @param result 风险检测结果
   */
  @Override
  public void handleRisk(FraudRiskResult result) {
    log.info("处理用户[{}]的风险，风险类型：{}，风险等级：{}",
        result.getUserAddress(), result.getRiskTypeDesc(), result.getRiskLevelDesc());

    // 使用风险处理链进行处理
    riskHandlerChain.handleRisk(result);
  }

  /**
   * AI分析核心方法
   */
  private FraudRiskResult analyzeWithAI(FraudDetectionInput input) {
    String prompt = buildDetectionPrompt(input);

    String aiResponse = aiService.chatWithAI(prompt);

    FraudRiskResult result = parseAIResponse(aiResponse);
    result.setUserAddress(input.getUserProfile().getUserAddress());
    result.setUserProfile(input.getUserProfile());
    result.setDetectionTime(LocalDateTime.now());

    return result;
  }

  /**
   * 构建AI检测提示词
   */
  private String buildDetectionPrompt(FraudDetectionInput input) {
    return String.format("""
        请分析以下社保账户的欺诈风险：
        用户特征：%s | 年龄：%d | 参保地：%s
        近一年缴费记录：%s
        区块链操作记录：%s
        登录日志：%s
        操作日志：%s
        转移记录：%s
        请分析以下三种欺诈风险类型：
        1. 身份冒用风险：生物特征匹配差异率>15%%或登录设备/地点突变
        2. 资金异常风险：月缴费基数波动>30%%或缴费频次异常（如单日多次缴费）
        3. 地域冲突风险：同期多地参保或转移间隔<6个月
        要求输出：风险评分(0-100)、风险类型(1-身份冒用,2-资金异常,3-地域冲突)、风险等级(0-低,1-中,2-高)、证据摘要、建议处置措施
        只能按照以下格式输出，不要多，也不要少:风险评分(0-100)、风险类型(1-身份冒用,2-资金异常,3-地域冲突)、风险等级(0-低,1-中,2-高)、证据摘要、建议处置措施
        示例输出：风险评分:85、风险类型:2、风险等级:2、证据摘要:xxx、建议措施:xxx
        """,
        input.getUserProfile().getMaskedId(),
        input.getUserProfile().getAge(),
        input.getUserProfile().getLocation(),
        formatPaymentData(input.getPaymentRecords()),
        formatBlockchainOps(input.getBlockchainOps()),
        formatLoginLogs(input.getLoginLogs()),
        formatOperationLogs(input.getOperationLogs()),
        formatTransferRecords(input.getTransferRecords()));
  }

  /**
   * 解析AI响应
   */
  private FraudRiskResult parseAIResponse(String aiResponse) {
    // 这里简化处理，实际应该使用正则表达式或JSON解析
    // 假设AI返回格式为："风险评分:85、风险类型:2、风险等级:2、证据摘要:xxx、建议措施:xxx"
    String[] parts = aiResponse.split("、");

    FraudRiskResult result = new FraudRiskResult();
    for (String part : parts) {
      String[] keyValue = part.split(":");
      if (keyValue.length == 2) {
        String key = keyValue[0].trim();
        String value = keyValue[1].trim();

        switch (key) {
          case "风险评分":
            result.setScore(Integer.parseInt(value));
            result.setRiskLevel(FraudRiskResult.calculateRiskLevel(Integer.parseInt(value)));
            break;
          case "风险类型":
            result.setRiskType(Integer.parseInt(value));
            switch (Integer.parseInt(value)) {
              case 1:
                result.setRiskTypeDesc("身份冒用");
                break;
              case 2:
                result.setRiskTypeDesc("资金异常");
                break;
              case 3:
                result.setRiskTypeDesc("地域冲突");
                break;
              default:
                result.setRiskTypeDesc("未知风险");
            }
            break;
          case "证据摘要":
            result.setEvidenceSummary(value);
            break;
          case "建议措施":
            result.setSuggestedAction(value);
            break;
        }
      }
    }

    return result;
  }

  /**
   * 格式化缴费记录数据
   */
  private String formatPaymentData(List<PaymentRecord> records) {
    if (records == null || records.isEmpty()) {
      return "无缴费记录";
    }

    StringBuilder sb = new StringBuilder();
    for (PaymentRecord record : records) {
      sb.append(record.getPaymentMonth())
          .append(":基数=").append(record.getPaymentBase())
          .append(",金额=").append(record.getPaymentAmount())
          .append(",方式=").append(record.getPaymentMethod())
          .append(" | ");
    }
    return sb.toString();
  }

  /**
   * 格式化区块链操作记录
   */
  private String formatBlockchainOps(List<BlockchainOp> ops) {
    if (ops == null || ops.isEmpty()) {
      return "无区块链操作记录";
    }

    StringBuilder sb = new StringBuilder();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    for (BlockchainOp op : ops) {
      sb.append(formatter.format(op.getOpTime()))
          .append(":类型=").append(op.getOpType())
          .append(",地点=").append(op.getOpLocation())
          .append(",设备=").append(op.getDeviceInfo())
          .append(" | ");
    }
    return sb.toString();
  }

  /**
   * 格式化登录日志
   */
  private String formatLoginLogs(List<LoginLog> logs) {
    if (logs == null || logs.isEmpty()) {
      return "无登录日志";
    }

    StringBuilder sb = new StringBuilder();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    for (LoginLog log : logs) {
      sb.append(
          formatter.format(log.getLoginTime().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime()))
          .append(":IP=").append(log.getLoginIp())
          .append(",地点=").append(log.getLoginLocation())
          .append(",设备=").append(log.getBrowser()).append("/").append(log.getOs())
          .append(" | ");
    }
    return sb.toString();
  }

  /**
   * 格式化操作日志
   */
  private String formatOperationLogs(List<OperationLog> logs) {
    if (logs == null || logs.isEmpty()) {
      return "无操作日志";
    }

    StringBuilder sb = new StringBuilder();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    for (OperationLog log : logs) {
      sb.append(formatter
          .format(log.getOperationTime().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime()))
          .append(":模块=").append(log.getModule())
          .append(",操作=").append(log.getOperation())
          .append(",IP=").append(log.getIp())
          .append(" | ");
    }
    return sb.toString();
  }

  /**
   * 格式化转移记录
   */
  private String formatTransferRecords(List<TransferRecord> records) {
    if (records == null || records.isEmpty()) {
      return "无转移记录";
    }

    StringBuilder sb = new StringBuilder();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    for (TransferRecord record : records) {
      sb.append(formatter
          .format(record.getApplicationDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime()))
          .append(":从=").append(record.getFromBureauAddress())
          .append(",到=").append(record.getToBureauAddress())
          .append(",状态=").append(record.getApprovalStatus())
          .append(" | ");
    }
    return sb.toString();
  }
}